package com.molichuxing.services.business.service.impl;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import com.molichuxing.framework.dto.TabDto;
import com.molichuxing.framework.exception.BizException;
import com.molichuxing.framework.utils.ObjectCastUtil;
import com.molichuxing.services.business.dto.request.modify.YearlyInspectionModifyBizDto;
import com.molichuxing.services.business.dto.response.YearlyInspectionBizDto;
import com.molichuxing.services.business.dto.response.YearlyInspectionLogBizDto;
import com.molichuxing.services.exception.VehicleExceptionCodeEnum;
import com.molichuxing.services.infrastructure.dto.request.create.YearlyInspectionCreateDto;
import com.molichuxing.services.infrastructure.dto.request.create.YearlyInspectionLogCreateDto;
import com.molichuxing.services.infrastructure.dto.request.modify.YearlyInspectionModifyDto;
import com.molichuxing.services.infrastructure.dto.response.*;
import com.molichuxing.services.infrastructure.service.*;
import com.molichuxing.services.property.CarInsuranceTypeEnum;
import com.molichuxing.services.property.YearlyInspectHandleStatusEnum;
import com.molichuxing.services.property.YearlyInspectHandleWayEnum;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.molichuxing.framework.dto.Paged;
import com.molichuxing.services.business.convertor.Convert;
import com.molichuxing.services.business.dto.response.CarYearlyInspectDto;
import com.molichuxing.services.business.service.CarYearlyInspectionBizService;
import com.molichuxing.services.property.CarYearlyInspectStatusEnum;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * 年检列表服务实现类
 *
 * @author xuelin yi
 */
@Service("carYearlyInspectionBizService")
public class CarYearlyInspectBizServiceImpl implements CarYearlyInspectionBizService {

    private static final Logger log = LoggerFactory.getLogger(CarYearlyInspectBizServiceImpl.class);

    @Resource
    private CarService carService;
    @Resource
    private CarViolationService carViolationService;

    @Resource
    private LicencePlateService licencePlateService;

    @Resource
    private InsuranceService insuranceService;

    @Resource
    private YearlyInspectService yearlyInspectService;

    @Resource
    private YearlyInspectionLogService yearlyInspectionLogService;

    @Override
    public Paged<CarYearlyInspectDto> getYearlyInspect(CarYearlyInspectStatusEnum carYearlyInspectStatusEnum, String licencePlate, String vin,
                                                       Integer stockId, String inspectStartDate, String inspectEndDate, Integer handleStatus, String sortName, String sortWay, Integer pageNum, Integer pageSize) {
        log.info("根据查询条件获取年检列表信息 carYearlyInspectStatusEnum ： [" + carYearlyInspectStatusEnum + "]");
        Paged<CarYearlyInspectDto> paged = new Paged<>();
        paged.setTab(getTabList());
        List<Integer> carIds = null;
        if (null != licencePlate || vin != null || stockId != null) {
            List<CarDto> carDtoList = carService.getCarListBySearch(vin, licencePlate, stockId);
            if (carDtoList == null || carDtoList.size() == 0) {
                return paged;
            }
            carIds = new ArrayList<>();
            for (CarDto carDto : carDtoList) {
                carIds.add(carDto.getId());
            }
        }
        Paged<YearlyInspectionDto> result = yearlyInspectService.getYearlyInspectionPage(carYearlyInspectStatusEnum, carIds, stockId, inspectStartDate, inspectEndDate, handleStatus, sortName, sortWay, pageNum, pageSize);
        Map<Integer, Integer> logCountMap = null;
        List<YearlyInspectionDto> resultList = result.getList();
        if (resultList != null) {
            List<Integer> carIdList = new ArrayList<>();
            for (YearlyInspectionDto yearlyInspectionDto : resultList) {
                Integer carId = yearlyInspectionDto.getCarId();
                carIdList.add(carId);
            }
            logCountMap = yearlyInspectionLogService.getYearlyInspectionLogCount(carIdList);
        }

        paged.setList(Convert.toCarYearlyInspectDto(result.getList(), getCarList(result.getList()), logCountMap));
        paged.setTotal(result.getTotal());
        paged.setPageSize(pageSize);
        return paged;
    }

    @Override
    public int createYearlyInspection(YearlyInspectionCreateDto createDto) throws Exception {
        CarDto carDto = carService.getCarById(createDto.getCarId());
        if (null == carDto) {
            throw new BizException(VehicleExceptionCodeEnum.NOT_EXIST.getCode(), VehicleExceptionCodeEnum.NOT_EXIST.getMessage());
        }
        if (!carDto.getIsHavePlate()) {
            throw new BizException(VehicleExceptionCodeEnum.NOT_LICENCE_PLATE.getCode(), VehicleExceptionCodeEnum.NOT_LICENCE_PLATE.getMessage());
        }
        return yearlyInspectService.createYearlyInspection(createDto);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Boolean modifyYearlyInspection(YearlyInspectionModifyDto modifyDto) throws Exception {
        Integer handleWay = modifyDto.getHandleWay();
        CarDto carDto = carService.getCarById(modifyDto.getCarId());
        if (null == carDto) {
            throw new BizException(VehicleExceptionCodeEnum.NOT_EXIST.getCode(), VehicleExceptionCodeEnum.NOT_EXIST.getMessage());
        }
        if (!carDto.getIsHavePlate()) {
            throw new BizException(VehicleExceptionCodeEnum.NOT_LICENCE_PLATE.getCode(), VehicleExceptionCodeEnum.NOT_LICENCE_PLATE.getMessage());
        }
        YearlyInspectionDto yearlyInspectionDto = yearlyInspectService.getYearlyInspectionByCarId(modifyDto.getCarId());
        if (handleWay != null && YearlyInspectHandleWayEnum.USER_HANDLE.getValue() == handleWay
                && modifyDto.getEndDate().isBefore(yearlyInspectionDto.getEndDate())) {
            throw new BizException(VehicleExceptionCodeEnum.YEARLY_INSPECT_ERROR.getCode(), VehicleExceptionCodeEnum.YEARLY_INSPECT_ERROR.getMessage());
        }

        int result = yearlyInspectService.modifyYearlyInspection(modifyDto);
        if (handleWay != null && YearlyInspectHandleWayEnum.USER_HANDLE.getValue() == handleWay) {
            YearlyInspectionLogCreateDto yearlyInspectionLogCreateDto = Convert.toYearlyInspectionLogCreateDto(yearlyInspectionDto, modifyDto);
            yearlyInspectionLogService.createYearlyInspectionLog(yearlyInspectionLogCreateDto);
        }

        if (result > 0) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public YearlyInspectionBizDto getYearlyInspection(Integer carId) {
        YearlyInspectionDto yearlyInspectionDto = yearlyInspectService.getYearlyInspectionByCarId(carId);
        if (null == yearlyInspectionDto) {
            return null;
        }

        CarDto carDto = carService.getCarById(carId);
        if (null == carDto) {
            throw new BizException("车辆不存在");
        }

        YearlyInspectionLogDto yearlyInspectionLogDto = null;
        Integer handleStatus = yearlyInspectionDto.getHandleStatus();
        if (handleStatus != null && YearlyInspectHandleStatusEnum.HAVE_UPDATE.getValue() == handleStatus) {
            yearlyInspectionLogDto = yearlyInspectionLogService.getNewYearlyInspectionLogByCarId(carId);
        }

        Integer violationCount = carViolationService.getViolationCountByCarId(carId);

        LicencePlateDto licencePlateDto = licencePlateService.getLicensePlateByCarId(carId);
        InsuranceDto insuranceDto = insuranceService.getInsuranceByCarIdAndType(carId, CarInsuranceTypeEnum.COMPULSORY_INSURANCE.getValue());
        return Convert.toYearlyInspectionBizDto(yearlyInspectionDto, carDto, licencePlateDto, insuranceDto, violationCount, yearlyInspectionLogDto);
    }

    @Override
    public List<CarYearlyInspectDto> getYearlyInspectDownload(List<String> inspectionIdList, CarYearlyInspectStatusEnum carYearlyInspectStatusEnum, String licencePlate, String vin,
                                                              Integer stockId, String inspectStartDate, String inspectEndDate) {
        List<Integer> carIds = null;
        if (null != licencePlate || vin != null || stockId != null) {
            List<CarDto> carDtoList = carService.getCarListBySearch(vin, licencePlate, stockId);
            if (carDtoList == null || carDtoList.size() == 0) {
                return null;
            }
            carIds = new ArrayList<>();
            for (CarDto carDto : carDtoList) {
                carIds.add(carDto.getId());
            }
        }
        List<YearlyInspectionDto> result = yearlyInspectService.getYearlyInspectionList(inspectionIdList, carYearlyInspectStatusEnum, carIds, stockId, inspectStartDate, inspectEndDate);
        return Convert.toCarYearlyInspectDto(result, getCarList(result), null);
    }

    @Override
    public long getYearlyInspectDownloadCount(List<String> inspectionIdList, CarYearlyInspectStatusEnum carYearlyInspectStatusEnum, String licencePlate, String vin, Integer stockId, String inspectStartDate, String inspectEndDate) {
        List<Integer> carIds = null;
        if (null != licencePlate || vin != null || stockId != null) {
            List<CarDto> carDtoList = carService.getCarListBySearch(vin, licencePlate, stockId);
            if (carDtoList == null || carDtoList.size() == 0) {
                return 0;
            }
            carIds = new ArrayList<>();
            for (CarDto carDto : carDtoList) {
                carIds.add(carDto.getId());
            }
        }
        return yearlyInspectService.getYearlyInspectDownloadCount(inspectionIdList, carYearlyInspectStatusEnum, carIds, stockId, inspectStartDate, inspectEndDate);
    }

    private Map<Integer, CarDto> getCarList(List<YearlyInspectionDto> yearlyInspectionList) {
        if (null == yearlyInspectionList || yearlyInspectionList.size() < 1) {
            return new HashMap<>();
        }
        List<Integer> carIds = yearlyInspectionList.stream().map(YearlyInspectionDto::getCarId).collect(Collectors.toList());
        return carService.getCarByIds(carIds);
    }

    private List<TabDto> getTabList() {
        List<TabDto> tabList = new ArrayList<>();
        for (CarYearlyInspectStatusEnum statusEnum : CarYearlyInspectStatusEnum.values()) {
            int count = yearlyInspectService.getYearlyInspectCount(statusEnum);
            TabDto tabDto = new TabDto();
            tabDto.setCount(count);
            tabDto.setName(statusEnum.getName());
            tabDto.setType(statusEnum.getValue());
            tabList.add(tabDto);
        }
        return tabList;
    }

    @Override
    public List<YearlyInspectionLogBizDto> getYearlyInspectionLogListByCarId(Integer carId) {
        List<YearlyInspectionLogDto> yearlyInspectionLogList = yearlyInspectionLogService.getYearlyInspectionLogListByCarId(carId);
        CarDto carDto = carService.getCarById(carId);
        return Convert.toYearlyInspectionLogDto(yearlyInspectionLogList, carDto);
    }

    /**
     * 修改年检
     *
     * @param yearlyInspectionModifyBizList
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Boolean modifyYearlyInspection(List<YearlyInspectionModifyBizDto> yearlyInspectionModifyBizList) {
        if (null == yearlyInspectionModifyBizList || yearlyInspectionModifyBizList.size() < 1) {
            return true;
        }

        List<YearlyInspectionModifyBizDto> modifyList = new ArrayList<>();
        List<Integer> carIdList = new ArrayList<>();

        for (YearlyInspectionModifyBizDto yearlyInspectionModifyBizDto : yearlyInspectionModifyBizList) {
            Integer handleStatus = yearlyInspectionModifyBizDto.getHandleStatus();
            if (YearlyInspectHandleStatusEnum.SEND_BACK.getValue() == handleStatus) {
                modifyList.add(yearlyInspectionModifyBizDto);
            } else if (YearlyInspectHandleStatusEnum.HAVE_UPDATE.getValue() == handleStatus) {
                modifyList.add(yearlyInspectionModifyBizDto);
                carIdList.add(yearlyInspectionModifyBizDto.getCarId());
            }
        }

        List<YearlyInspectionDto> yearlyInspectionList = yearlyInspectService.getYearlyInspectionListByCarId(carIdList);
        if (yearlyInspectionList != null && yearlyInspectionList.size() > 0) {
            for (YearlyInspectionDto yearlyInspectionDto : yearlyInspectionList) {
                LocalDateTime endDate = yearlyInspectionDto.getEndDate();
                yearlyInspectionDto.setEndDate(endDate.plusYears(2L));
            }

            Map<Integer, YearlyInspectionDto> yearlyInspectionMap = yearlyInspectionList.stream().collect(Collectors.toMap(YearlyInspectionDto::getCarId, a -> a, (k1, k2) -> k1));
            for (YearlyInspectionModifyBizDto yearlyInspectionModifyBizDto : modifyList) {
                Integer carId = yearlyInspectionModifyBizDto.getCarId();
                YearlyInspectionDto yearlyInspectionDto = yearlyInspectionMap.get(carId);
                if (null == yearlyInspectionDto) {
                    continue;
                }
                LocalDateTime endDate = yearlyInspectionDto.getEndDate();
                yearlyInspectionModifyBizDto.setEndDate(endDate);
            }
            List<YearlyInspectionLogCreateDto> yearlyInspectionLogList = Convert.toYearlyInspectionLogCreateDto(yearlyInspectionList, modifyList);
            yearlyInspectionLogService.createYearlyInspectionLogBatch(yearlyInspectionLogList);
        }

        List<YearlyInspectionModifyDto> yearlyInspectionModifyList = Convert.toYearlyInspectionModifyDto(modifyList);
        return yearlyInspectService.modifyYearlyInspectionBatch(yearlyInspectionModifyList);
    }


}
